package com.divemotor.ventarepuestosinternet.dao.impl;

import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.divemotor.ventarepuestosinternet.beans.adapter.CotizacionAdapter;
import com.divemotor.ventarepuestosinternet.beans.adapter.ElementoCotizacionAdapter;
import com.divemotor.ventarepuestosinternet.beans.form.CotizacionBeanForm;
import com.divemotor.ventarepuestosinternet.dao.CotizacionDAO;
import com.divemotor.ventarepuestosinternet.model.Cotizacion;
import com.divemotor.ventarepuestosinternet.model.EstadoCotizacion;
import com.divemotor.ventarepuestosinternet.model.Sucursal;
import com.divemotor.ventarepuestosinternet.model.Supervisor;
import com.divemotor.ventarepuestosinternet.model.Usuario;
import com.divemotor.ventarepuestosinternet.model.Vendedor;
import com.divemotor.ventarepuestosinternet.util.Constantes;
import com.divemotor.ventarepuestosinternet.util.DatosDeSession;
import com.divemotor.ventarepuestosinternet.util.Paginacion;

@SuppressWarnings("unchecked")
@Repository(value = "cotizacionDAO")
public class CotizacionDAOImpl implements CotizacionDAO {

	@Autowired
	private SessionFactory sessionFactory;
	
	@Override
	public Cotizacion guardar(Cotizacion cotizacion) {
		sessionFactory.getCurrentSession().persist(cotizacion);
		return cotizacion;
	}

	@Override
	public List<Cotizacion> listarPorUsuario(Integer idUsuario) {
		return sessionFactory.getCurrentSession().getNamedQuery("Cotizacion.usuario")
												 .setParameter("idUsuario", idUsuario)
												 .list();
	}

    @Override
	public Cotizacion obtenerPorId(Integer idCotizacion) {
		return (Cotizacion) sessionFactory.getCurrentSession().get(Cotizacion.class, idCotizacion);
	}
    
    @Override
    public List<ElementoCotizacionAdapter> obtenerDetalleRepuesto(Integer idCotizacion){
    	Query q = sessionFactory.getCurrentSession().getNamedQuery("Cotizacion.detalleElementoRepuesto");
    	q.setParameter("idCotizacion", idCotizacion);
    	return q.list();
    }
    
    @Override
    public List<ElementoCotizacionAdapter> obtenerDetallePromocion(Integer idCotizacion){
    	Query q = sessionFactory.getCurrentSession().getNamedQuery("Cotizacion.detalleElementoPromocion");
    	q.setParameter("idCotizacion", idCotizacion);
    	return q.list();
    }
    
    @Override
    public List<ElementoCotizacionAdapter> obtenerElementosCotizacionRepuesto(Integer idCotizacion){
    	Query q = sessionFactory.getCurrentSession().getNamedQuery("Cotizacion.listarElementosRepuestos");
    	q.setParameter("idCotizacion", idCotizacion);
    	return q.list();
    }
    
    @Override
    public List<ElementoCotizacionAdapter> obtenerElementosCotizacionPromocion(Integer idCotizacion){
    	Query q = sessionFactory.getCurrentSession().getNamedQuery("Cotizacion.listarElementosPromocion");
    	q.setParameter("idCotizacion", idCotizacion);
    	return q.list();
    }
    
    @Override
    public List<CotizacionAdapter> obtenerCotizacionesAdapter(){
    	Query q = sessionFactory.getCurrentSession().getNamedQuery("Cotizacion.listarCotizacion");
    	return q.list();
    }
    
    @Override
    public List<ElementoCotizacionAdapter> obtenerElementosCotizacion(Integer idCotizacion){
    	List<ElementoCotizacionAdapter> lista = obtenerElementosCotizacionRepuesto(idCotizacion);
    	lista.addAll(obtenerElementosCotizacionPromocion(idCotizacion));
    	return lista;
    }
    
	@Override	
	public List<Cotizacion> listar() {
		Criteria  criteria = sessionFactory.getCurrentSession().createCriteria(Cotizacion.class);
		return criteria.list();
	}

	@Override
	public List<Cotizacion> listarPorSupervisor(Supervisor supervisor) {
		Supervisor supervisorB = new Supervisor();
		Criteria  criteria = sessionFactory.getCurrentSession().createCriteria(Supervisor.class);
		criteria.add(Restrictions.eq("usuario", supervisor.getUsuario()));
		criteria.add(Restrictions.not(Restrictions.eq("estado", Constantes.ESTADO_ELIMINADO)));
		supervisorB = (Supervisor)criteria.uniqueResult();
		
		if(supervisorB.getListaSucursal().size() > 0 || supervisorB.getListaSucursal() == null ){
			Criteria criteria2 = sessionFactory.getCurrentSession().createCriteria(Cotizacion.class,"cotizacion");
			criteria2.createAlias("cotizacion.sucursal","sucursal");
			criteria2.add(Restrictions.in("sucursal",supervisorB.getListaSucursal()));
			return criteria2.list();
		}else{
			return null;
		}
	}

	@Override
	public List<EstadoCotizacion> obtenerEstadosCotizacionPorUsuarioSucursal(Usuario usuarioAutenticado) {
	    Criteria  criteria = sessionFactory.getCurrentSession().createCriteria(EstadoCotizacion.class);
		return criteria.list();
	}

	@Override
	public List<Vendedor> obtenerVendedoresPorUsuarioSucursal(
			Usuario usuarioAutenticado) {
		Supervisor supervisorB = new Supervisor();
		  
	    Criteria  criteria = sessionFactory.getCurrentSession().createCriteria(Supervisor.class);
	    criteria.add(Restrictions.eq("usuario", usuarioAutenticado));
	    criteria.add(Restrictions.not(Restrictions.eq("estado", Constantes.ESTADO_ELIMINADO)));
	    supervisorB = (Supervisor)criteria.uniqueResult();
	
	    if(supervisorB.getListaSucursal().size() > 0 || supervisorB.getListaSucursal() == null ){
			Criteria criteria2 = sessionFactory.getCurrentSession().createCriteria(Cotizacion.class,"cotizacion");
			criteria2.createAlias("cotizacion.sucursal","sucursal");
			criteria2.createAlias("cotizacion.vendedor","vendedor");
			criteria2.setProjection(Projections.distinct(Projections.property("vendedor")));
			criteria2.add(Restrictions.in("sucursal",supervisorB.getListaSucursal()));
			return criteria2.list();
		}else{
			return null;
		}
	}
	
	@Override
	public List<CotizacionAdapter> buscar(CotizacionBeanForm cotizacionBeanForm) {
		return buscarAdapter(null, cotizacionBeanForm, true);
	}
	
	public List<CotizacionAdapter> buscarVendedorAdapter(Paginacion paginacion, CotizacionBeanForm cotizacionBeanForm){
		return buscarAdapter(paginacion, cotizacionBeanForm, false);
	}
	
	public List<CotizacionAdapter> buscarAdapter(Paginacion paginacion, CotizacionBeanForm cotizacionBean, boolean flagTipoPerfil) {					
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Cotizacion.class, "cotizacion");
		criteria.createAlias("cotizacion.sucursal","sucursal");
		criteria.createAlias("sucursal.departamento","departamento"); 
		criteria.createAlias("sucursal.provincia", "provincia");
		criteria.createAlias("sucursal.distrito", "distrito");
		criteria.createAlias("cotizacion.estadoCotizacion", "estadoCotizacion");
		criteria.createAlias("cotizacion.usuarioCliente", "usuarioCliente");
		criteria.createAlias("usuarioCliente.cliente", "cliente");
		
		if(flagTipoPerfil){
			criteria.createAlias("cotizacion.vendedor", "vendedor",JoinType.LEFT_OUTER_JOIN);
			criteria.createAlias("vendedor.usuario", "usuario",JoinType.LEFT_OUTER_JOIN);
		}
		
		construirProyeccionCotizacion(criteria, flagTipoPerfil);
		construirRestriccionCotizacion(cotizacionBean, criteria);
		
		if(paginacion != null){
			criteria.setFirstResult(paginacion.getInicioPagina());
			criteria.setMaxResults(paginacion.getFinPagina());
		
			if (paginacion.getOrdenarLabel() != null) {
				if (paginacion.getDireccionOrden().equals(Constantes.ORDEN_DEFAULT)) {
					criteria.addOrder(Order.desc(paginacion.getOrdenarLabel()));
				} else {
					criteria.addOrder(Order.desc(paginacion.getOrdenarLabel()));
				}	
			} else {
				criteria.addOrder(Order.desc("idCotizacion"));
			}
		}else{
			criteria.addOrder(Order.desc("idCotizacion"));
		}
		criteria.setResultTransformer(Transformers.aliasToBean(CotizacionAdapter.class));
		return criteria.list();
	}
	
	@Override
	public int cantidadCotizaciones() {
		Supervisor supervisorB = new Supervisor();
		  
		Criteria  criteria2 = sessionFactory.getCurrentSession().createCriteria(Supervisor.class);
		criteria2.add(Restrictions.eq("usuario", DatosDeSession.obtenerUsuarioAutenticado()));
		criteria2.add(Restrictions.not(Restrictions.eq("estado", Constantes.ESTADO_ELIMINADO)));
		supervisorB = (Supervisor)criteria2.uniqueResult();
		
		if(supervisorB.getListaSucursal().size() > 0 || supervisorB.getListaSucursal() == null ){
           Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Cotizacion.class,"cotizacion");
	       criteria.setProjection(Projections.count("cotizacion.idCotizacion"));
	       criteria.createAlias("cotizacion.sucursal", "sucursalPermitidas");
		   criteria.add(Restrictions.in("sucursal",supervisorB.getListaSucursal()));
       	   Number result = (Number) criteria.uniqueResult();
		   return result.intValue();
		}else{
		   return 0;
		}
	}

	@Override
	public void actualizar(Cotizacion cotizacion) {
		sessionFactory.getCurrentSession().merge(cotizacion);
	}

	@Override
	public int cantidadCotizaciones(CotizacionBeanForm cotizacionBean, boolean flagTipoPerfil) {
		if(CollectionUtils.isNotEmpty(cotizacionBean.getListaSucursales())){
	     	Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Cotizacion.class,"cotizacion");
	     	criteria.createAlias("cotizacion.sucursal","sucursal");
			criteria.createAlias("sucursal.departamento","departamento"); 
			criteria.createAlias("sucursal.provincia", "provincia");
			criteria.createAlias("sucursal.distrito", "distrito");
			criteria.createAlias("cotizacion.estadoCotizacion", "estadoCotizacion");
			
			if(flagTipoPerfil){
				criteria.createAlias("cotizacion.vendedor", "vendedor",JoinType.LEFT_OUTER_JOIN);
				criteria.createAlias("vendedor.usuario", "usuario",JoinType.LEFT_OUTER_JOIN);
			}
			
	        criteria.setProjection(Projections.count("cotizacion.idCotizacion"));
	        construirRestriccionCotizacion(cotizacionBean, criteria);
			Number result = (Number) criteria.uniqueResult();
			return result.intValue();
		}else{
			return 0;
		}
	}
	
	private void construirProyeccionCotizacion(Criteria criteria, boolean flagTipoPerfil){
		ProjectionList lista = Projections.projectionList();
		lista.add(Projections.property("idCotizacion"), "idCotizacion")
			 .add(Projections.property("fechaCreacion"),"fechaCreacion")
			 .add(Projections.property("cliente.nombre"),"nombreCliente")
			 .add(Projections.property("departamento.nombre"),"nombreDepartamento")
			 .add(Projections.property("provincia.nombre"),"nombreProvincia")
			 .add(Projections.property("distrito.nombre"),"nombreDistrito")
			 .add(Projections.property("sucursal.nombre"),"nombreSucursal")
			 .add(Projections.property("estadoCotizacion.nombre"),"estado")
			 .add(Projections.property("estadoCotizacion.idEstadoCotizacion"),"idEstadoCotizacion")
			 .add(Projections.property("observacion"),"observacion");
		
		if(flagTipoPerfil){
			lista.add(Projections.property("usuario.nombres"),"nombreVendedor")
				 .add(Projections.property("usuario.apellidos"),"apellidoVendedor")
				 .add(Projections.property("vendedor.idVendedor"),"idVendedor");
		}
		
		criteria.setProjection(lista);
	}
	
	private void construirRestriccionCotizacion(CotizacionBeanForm cotizacionBeanForm, Criteria criteria){
		String numSolicitud 		= cotizacionBeanForm.getNumSolicitud();
		Integer departamento 		= cotizacionBeanForm.getIdDepartamento();
		Integer provincia 			= cotizacionBeanForm.getIdProvincia();
		Integer distrito 			= cotizacionBeanForm.getIdDistrito();	
		Integer sucursal 			= cotizacionBeanForm.getIdSucursal();
		Integer idEstadoCotizacion 	= cotizacionBeanForm.getIdEstadoCotizacion();
		Integer idVendedor 			= cotizacionBeanForm.getIdVendedor();
		Integer idUsuario			= cotizacionBeanForm.getIdUsuario();
		Date fechaInicio   			= cotizacionBeanForm.getFechaInicio();
		Date fechaFin	  	 		= cotizacionBeanForm.getFechaFin();
		List<Sucursal> sucursales   = cotizacionBeanForm.getListaSucursales();
		
		if(StringUtils.isNotBlank(numSolicitud)){
			criteria.add(Restrictions.eq("cotizacion.idCotizacion", Integer.parseInt(numSolicitud)));	
		}
		
		if((departamento != null) && (departamento != Constantes.NO_SELECCIONADO)){
			criteria.add(Restrictions.eq("departamento.idDepartamento", departamento));	
		}
		
		if((provincia != null) && (provincia != Constantes.NO_SELECCIONADO)){
			criteria.add(Restrictions.eq("provincia.idProvincia", provincia));
		}
		if ((distrito != null) && (distrito != Constantes.NO_SELECCIONADO)){
			criteria.add(Restrictions.eq("distrito.idDistrito", distrito));
		}
		if ((sucursal != null) && (sucursal != Constantes.NO_SELECCIONADO)){
			criteria.add(Restrictions.eq("sucursal.idSucursal", sucursal));
		}
		if ((idEstadoCotizacion != null) && (idEstadoCotizacion != Constantes.NO_SELECCIONADO)) {
			criteria.add(Restrictions.eq("estadoCotizacion.idEstadoCotizacion", idEstadoCotizacion));
		}
		
		if((idVendedor != null) && (idVendedor != Constantes.NO_SELECCIONADO)){
			criteria.add(Restrictions.eq("vendedor.idVendedor",idVendedor));
		}
		
		if(idUsuario != null){
			criteria.add(Restrictions.eq("usuarioCliente.usuario.idUsuario", idUsuario));
		}
		
		if(CollectionUtils.isNotEmpty(sucursales)){
			criteria.add(Restrictions.in("sucursal", cotizacionBeanForm.getListaSucursales()));
		}
		
		if ((fechaInicio != null) && (fechaFin != null)) {
			criteria.add(Restrictions.between("cotizacion.fechaCreacion", fechaInicio, fechaFin));
		} else if ((fechaInicio != null) && (fechaFin == null)) {
			criteria.add(Restrictions.ge("cotizacion.fechaCreacion", fechaInicio));
		} else if ((fechaInicio == null) && (fechaFin != null)) {
			criteria.add(Restrictions.le("cotizacion.fechaCreacion", fechaFin));
		}
	}
	
}
